//****************************************************************************
//						t_repeat
//
//功能：从输入时钟域切换到输出时钟域，输出显示数据，生成TCON信号
//版本：v1.0		yshao		2021/04/28
//
//版本：v1.1		yshao		2021/04/30
//								修正时序
//****************************************************************************

module t_repeat (
        //时钟 & 复位
        input   wire            resetb,
        input	wire 			lvds_ok,
        //输入信号
        input   wire	[1:0]	ckin,
        input   wire	[1:0]	vsin,
        input   wire	[1:0]	hsin,
        input   wire	[1:0]	dein,
        input   wire	[47:0]	din,

        //显示数据输出
        input	wire            clk2x,
        input	wire            dsync,
(*keep*)output  reg				deout,
(*keep*)output  reg		[47:0]	dout,
        
        //TCON辅助时序
		output	reg				POL,
		output	reg				CPV,
		output	reg				TP,
		output	reg				STV1,
		output	reg				STV2,
		output	reg				OE1,
		output	reg				SHL,
		output	reg				PAIR,
		output	reg				XON,
		output	reg				UD,
		output	reg				S1_L,

        
        output  wire    [10:0]   tout
        );

//**************************************************************/
//               信号定义
//**************************************************************/
		wire	[11:0]	r_max;
		wire	[10:0]	b_max;

		reg		[ 3:0]	dein_t;
		reg		[ 2:0]	buf_w_sel, buf_r_sel;
		reg		[ 9:0]	w_count, r_count;
		reg		[ 1:0]	b_count;
		wire	[47:0]	buf_rdata;
(*keep*)reg				b_w_end, buf_we_a, buf_we_b, we_a_ext;//we_b_ext;
(*keep*)reg		[ 9:0]	buf_waddr_a, buf_waddr_b;
(*keep*)reg		[47:0]	buf_wdata_a, buf_wdata_b;

		reg		[ 4:0]	vs_t, hs_t, de_t;
		reg				h_sync, i_de_active, out_active, start_flag, out_flag, blank_flag, pre_flag;
		reg		[ 7:0]	o_de_active;

		reg		[21:0]	p_count;
		reg				r_flag, r_end, r_flag_t;

		reg		[12:0]	d_h_count, b_h_count;
		reg		[ 2:0]	p_h_count;
		reg		[21:0]	GOA_out_en_count;
		reg				p_count_sign; //p_count变为0时候的标记

		reg				GOA_out_en;
		reg				GOA_out2_en;
		reg		[ 7:0]	v_count;
 
//**************************************************************/
//			    参数设置
//**************************************************************/
assign	b_max = (1920 / 4) - 1;
assign	r_max = (1920 / 2);// - 2;


//**************************************************************/
//			    数据缓冲
//**************************************************************/
sram_4kw48_8kr24_sdp_so h_buf_a(
		.clka(ckin[0]),
		.cea(buf_we_a),
		.addra({buf_w_sel[2:0], buf_waddr_a[8:0]}),
		.dia(buf_wdata_a),

		.clkb(clk2x),
		.rstb(1'b0),
		.addrb({buf_r_sel[2:0], r_count[9:0]}),
		.dob(buf_rdata[23:0])
		);	
		
sram_4kw48_8kr24_sdp_so h_buf_b(		
		.clka(ckin[0]),
		.cea(buf_we_b),
		.addra({buf_w_sel[2:0], buf_waddr_b[8:0]}),
		.dia(buf_wdata_b),

		.clkb(clk2x),
		.rstb(1'b0),
		.addrb({buf_r_sel[2:0], r_count[9:0]}),
		.dob(buf_rdata[47:24])
		);

//************************************************/
//			    h_buf写入控制
//************************************************/
//de缓冲
always @(posedge ckin[0])
	dein_t <= {dein_t[2:0], dein[0]};
		
//写计数
always @(posedge ckin[0])
	if (dein[0] == 0)
		w_count <= 0;
	else if (b_w_end == 1)
		w_count <= 0;
	else	
		w_count <= w_count + 1;
		
//写分区结束
always @(posedge ckin[0])
	if (w_count == b_max)
		b_w_end <= 1;
	else
		b_w_end <= 0;
		
//写分区计数
always @(posedge ckin[0])
	if ((dein[0] == 0) && (dein_t[1] == 0))
		b_count <= 0;
	else if (b_w_end == 1)
		b_count <= b_count + 1;
		
//写分区选择
always @(posedge ckin[0] or negedge resetb)
	if (resetb == 0)
		buf_w_sel <= 0;
	else if (vsin[0] == 1)
		buf_w_sel <= 0;
	else if ((dein_t[3:2] == 2'b10))		
		buf_w_sel <= buf_w_sel + 1;

//写使能A扩展
always @(posedge ckin[0])
	if ((b_w_end == 1) && (b_count == 0))
		we_a_ext <= 1;
	else
		we_a_ext <= 0;

//写使能A
always @(posedge ckin[0])
	if ((dein[0] == 1) && (b_count == 0))
		buf_we_a <= 1;
	else if (we_a_ext == 1)
		buf_we_a <= 1;
	else
		buf_we_a <= 0;

//写使能B
always @(posedge ckin[0])
	if ((dein_t[1] == 1) && (b_count == 1))
		buf_we_b <= 1;
//	else if (we_b_ext == 1)
//		buf_we_b <= 1;
	else
		buf_we_b <= 0;

//写地址A
always @(posedge ckin[0])
	if (buf_we_a == 1)
		buf_waddr_a <= buf_waddr_a + 1;
	else
		buf_waddr_a <= 0;

//写地址B
always @(posedge ckin[0])
	if (buf_we_b == 1)
		buf_waddr_b <= buf_waddr_b + 1;
	else
		buf_waddr_b <= 0;

//************************************************/
//			    h_buf数据交换
//************************************************/
wire	[7:0]	r1, g1, b1, r2, g2, b2; 
wire	[7:0]	r1_a, g1_a, b1_a, r2_a, g2_a, b2_a; 
reg		[47:0]	din_a;

//数据延时
always @(posedge ckin[0])
	din_a <= din;

assign	r1 = din[7:0];
assign	g1 = din[15:8];
assign	b1 = din[23:16];
assign	r2 = din[31:24];
assign	g2 = din[39:32];
assign	b2 = din[47:40];

assign	r1_a = din_a[7:0];  
assign	g1_a = din_a[15:8]; 
assign	b1_a = din_a[23:16];
assign	r2_a = din_a[31:24];
assign	g2_a = din_a[39:32];
assign	b2_a = din_a[47:40];

//写数据A
always @(posedge ckin[0])
	if (buf_w_sel[0] == 1)
//		buf_wdata_a <= {8'h00, 8'hFF, 8'h00, 8'h00, 8'hFF, 8'h00};
		buf_wdata_a <= {b2_a, g2_a, r2_a, b1_a, g1_a, r1_a};
	else
//		buf_wdata_a <= {g2_a, r2_a, b2_a, g1_a, r1_a, b1_a};
//		buf_wdata_a <= {8'h00, 8'h00, 8'hFF, 8'h00, 8'h00, 8'hFF};
		buf_wdata_a <= {g2_a, r2_a, b1, g1_a, r1_a, b2_a};

//写数据B
always @(posedge ckin[0])
	if (buf_w_sel[0] == 1)
//		buf_wdata_b <= {g2_a, r2_a, b2_a, g1_a, r1_a, b1_a};
		buf_wdata_b <= {b2_a, g2_a, r2_a, b1_a, g1_a, r1_a};
	else
		buf_wdata_b <= {g2_a, r2_a, b1, g1_a, r1_a, b2_a};

//************************************************/
//			    缓冲读出控制
//************************************************/
always  @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		v_count <= 0;
	else if(lvds_ok == 0)
		v_count <= 0;
	else if ((dsync == 1) && (vs_t[2:1] == 2'b01)) begin
		if (v_count[7] == 0)
			v_count <= v_count + 1;
		end

//信号缓冲
always @(posedge clk2x) 
	if (dsync == 1) begin
		vs_t <= {vs_t[3:0], vsin[0]};
		hs_t <= {hs_t[3:0], hsin[0]};
		de_t <= {de_t[3:0], dein[0]};
	end

//行同步
always @(posedge clk2x) 
	if (dsync == 1) begin
		if (hs_t[2:1] == 2'b01)
			h_sync <= 1;
		else
			h_sync <= 0;
	end

//行内时钟计数
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)begin
		p_count <= 0;
		p_count_sign <= 1'b0;
	end
	else if (dsync == 1) begin
		if (h_sync == 1)begin
			p_count <= 0;
			p_count_sign <= 1'b0;
		end
		else if (p_count[12] == 0)begin
			p_count <= p_count + 1;
			p_count_sign <= 1'b1;
		end
	end

//de输入有效检测
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		i_de_active <= 0;
	else if (dsync == 1) begin
		if (h_sync == 1)
			i_de_active <= 0;
		else if (de_t[1] == 1)
			i_de_active <= 1;
	end

//输出有效延时
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		o_de_active <= 0;
	else if (dsync == 1) begin
		if (h_sync == 1)
			o_de_active <= {o_de_active[6:0], i_de_active};
	end

//输出延时选择
always @(posedge clk2x) 
	if (dsync == 1) begin
		out_active <= o_de_active[3];
	end

//预输出使能
always @(posedge clk2x) 
	if (dsync == 1) begin
		if ((i_de_active == 1) && (o_de_active[0] == 0))
			start_flag <= 1;
		else
			start_flag <= 0;
	end

//预输出使能
always @(posedge clk2x) 
	if (dsync == 1) begin
		if ((o_de_active[0] == 1) && (out_active == 0))
			pre_flag <= 1;
		else
			pre_flag <= 0;
	end

//输出标志
always @(posedge clk2x) 
	if (dsync == 1) begin
		if (out_active == 1)
			out_flag <= 1;
		else
			out_flag <= 0;
	end
	
//空闲标志
always @(posedge clk2x) 
	if (dsync == 1) begin
		if ((o_de_active[0] == 0) && (out_active == 0))
			blank_flag <= 1;
		else
			blank_flag <= 0;
	end

//读标志
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		r_flag <= 0;
	else if (dsync == 1) begin
		if (h_sync == 1)
			r_flag <= 0;
		else if ((out_flag == 1) && (p_count == 38))
			r_flag <= 1;
		else if (r_end == 1)
			r_flag <=0;
	end
		
//读计数
always @(posedge clk2x) 
	if (dsync == 1) begin
		if (r_flag == 1)
			r_count <= r_count + 1;
		else
			r_count <= 0;
	end

//读结束
always @(posedge clk2x) 
	if (dsync == 1) begin
		if (r_count == r_max)
			r_end <= 1;
		else
			r_end <= 0;
	end
	
//读分区选择
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		buf_r_sel <= 0;
	else if (dsync == 1) begin
		if (out_flag == 0)
			buf_r_sel <= 0;
		else if (r_end == 1)
			buf_r_sel <= buf_r_sel + 1;
	end
		
//deout
always @(posedge clk2x) 
	if (dsync == 1) begin
		r_flag_t <= r_flag;
		deout <= r_flag_t;
	end

/* reg	r_flag_tt,r_flag_ttt;

always @(posedge clk2x) begin
	r_flag_t 	<= r_flag;
	r_flag_tt 	<= r_flag_t;
	r_flag_ttt 	<= r_flag_tt;
end

assign	deout	= r_flag || r_flag_ttt;
 */

//dout
always @(posedge clk2x) 
	if (dsync == 1) begin
		if (r_flag_t == 1)
			dout <= buf_rdata;
		else
			dout <= 0;
	end

//************************************************/
//			    输入时序分析
//************************************************/
//输入有效行计数
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		d_h_count <= 0;
	else if (dsync == 1) begin
		if (out_flag == 0)
			d_h_count <= 0;
		else if ((h_sync == 1) && (d_h_count[12] == 0))
			d_h_count <= d_h_count + 1;
	end
		
//输入无效行计数
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		b_h_count <= 0;
	else if (dsync == 1) begin
		if (blank_flag == 0)
			b_h_count <= 0;
		else if ((h_sync == 1) && (b_h_count[12] == 0))
			b_h_count <= b_h_count + 1;
	end
		
//有效行预先计数
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		p_h_count <= 0;
	else if (dsync == 1) begin
		if (pre_flag == 0)
			p_h_count <= 0;
		else if (h_sync == 1)
			p_h_count <= p_h_count + 1;
	end
		
//**************************************************************/
//              TCON输出时序
//**************************************************************/
always @(posedge clk2x or negedge resetb)
	if (resetb == 0)begin
		SHL   <= 1'b0;
		PAIR  <= 1'b0;
		XON   <= 1'b0;
		UD    <= 1'b0;
		S1_L  <= 1'b0;
	end
	else begin
		SHL   <= 1'b1;
		PAIR  <= 1'b1;
		XON   <= 1'b1;
		UD    <= 1'b1;
		S1_L  <= 1'b0;
	end
//完整帧时序输出使能

always @(posedge clk2x)
	if (resetb == 0)
		GOA_out2_en <= 1;
	else if (v_count > 'd40)
		GOA_out2_en <= 0;
	else
		GOA_out2_en <= 1;

always @(posedge clk2x)
	if (resetb == 0)
		GOA_out_en <= 0;
	else if (v_count > 'd40 + 'd2)
		GOA_out_en <= 1;
	else 
		GOA_out_en <= 0;

//mini LVDS 包同步
always @(posedge clk2x)
	if (resetb == 0)
		TP <= 0;
	else if(GOA_out_en == 0)
		TP <= 0;
	else if (dsync == 1) begin
		if (dsync == 1) begin
			if ((p_count > 'd1010) && (p_count < 'd1088))
		        TP <= 1'b1;
		    else
		        TP <= 1'b0;
		end
	end

//STV1
always  @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		STV1 <= 0;
	else if(GOA_out_en == 0)
		STV1 <= 0;
	else if (dsync == 1) begin
		if ((d_h_count == 6) && (p_count == 267 ))
	        STV1 <= 1;
		else if ((d_h_count == 7) && (p_count == 249))
	        STV1 <= 0;
	end

//CPV
always @(posedge clk2x) 
	if (resetb == 0)
		CPV <= 0;
	else if(GOA_out_en == 0)
		CPV <= 0;
	else if (dsync == 1) begin
		if((d_h_count == 'd1)&(p_count == 'd343))begin
			CPV <= 0;
		end
		else begin
			if (p_count == 'd343)
				CPV <= 1'b0;
			else if (p_count == 'd871)
				CPV <= 1'b1;
		end
	end
	
//OE1
always @(posedge clk2x) 
	if (resetb == 0)
		OE1 <= 0;
	else if (GOA_out2_en == 1)
		OE1 <= 1;
	else if((GOA_out2_en == 0) && (GOA_out_en == 0))
		OE1 <= 0;
	else if (dsync == 1) begin
		if (p_count == 'd871)
			OE1 <= 1;
		else if(p_count == 'd20)
			OE1 <= 0;
	end


//POL
always  @(posedge clk2x or negedge resetb)
	if (resetb == 0)
		POL <= 0;
	else if(GOA_out_en == 0)
		POL <= 0;
	else if (dsync == 1) begin
		if ((d_h_count == 1) && (p_count == 'd1006))
	        POL <= POL + 1;
	end
	

	
//************************************************/
//      调试信号
//************************************************/
assign  tout = {POL,CPV,TP,STV1,STV2,OE1,SHL,PAIR,XON,UD,S1_L};

endmodule
